package com.lagou.filter;

import com.lagou.feign.UserFeignClient;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.*;
import java.util.concurrent.*;

@Slf4j
@Component
@RefreshScope
public class SecurityFilter implements GlobalFilter, Ordered {
    private static final ScheduledExecutorService REPORT_WORKER = Executors.newScheduledThreadPool(1);
    //用于存储每个客户端ip每次请求的时间戳列表<ip,时间戳集合>
    public static Map<String, List<Long>> IP_TIMESTAMP_MAP = new ConcurrentHashMap<>();
    //时间限制
    private static Long timeLimit;
    //请求次数限制
    private static int countLimit;


    @Value("${security.request.timeLimit}")
    public void setTimeLimit(Long timeLimit) {
        log.info("通过setter注入的timeLimit值：" + timeLimit);
        this.timeLimit = timeLimit;
    }

    @Value("${security.request.countLimit}")
    public void setCountLimit(int countLimit) {
        log.info("通过setter注入的countLimit值：" + countLimit);
        this.countLimit = countLimit;
    }

    static {
        //每5秒执行一次定时任务清除过期请求
        REPORT_WORKER.scheduleWithFixedDelay(() -> {
            if (!IP_TIMESTAMP_MAP.isEmpty()) {
                Set<Map.Entry<String, List<Long>>> entries = IP_TIMESTAMP_MAP.entrySet();
                Iterator<Map.Entry<String, List<Long>>> iterator = entries.iterator();
                while (iterator.hasNext()) {
                    Map.Entry<String, List<Long>> next = iterator.next();
                    List<Long> timestamps = next.getValue();
                    log.info("ip:" + next.getKey() + "限制时间内的请求数：" + timestamps.size());
                    for (Long timestamp : timestamps) {
                        if (System.currentTimeMillis() - timestamp > timeLimit) {
                            timestamps.remove(timestamp);
                        }
                    }
                }
            }
        }, 5, 5, TimeUnit.SECONDS);
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 思路：获取客户端ip，判断是否在黑名单中，在的话就拒绝访问，不在的话就放行
        // 从上下文中取出request和response对象
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        // 从request对象中获取客户端ip
        String clientIp = request.getHeaders().get("X-Real-IP").get(0);
        //添加本次请求到map中
        List<Long> timestampList = IP_TIMESTAMP_MAP.get(clientIp);
        if (timestampList == null) {
            timestampList = new CopyOnWriteArrayList<>();
            IP_TIMESTAMP_MAP.put(clientIp, timestampList);
        }
        long currentTimeMillis = System.currentTimeMillis();
        //添加当前请求的时间戳
        timestampList.add(currentTimeMillis);
        //map中统计的时间戳数量
        int totalCount = timestampList.size();
        //过期的时间戳数量
        int expiredCount = 0;
        //判断集合中的请求是否都在要求的时间范围内,统计过期的数量
        for (Long timestamp : timestampList) {
            if (currentTimeMillis - timestamp > timeLimit) {
                expiredCount++;
            } else {
                break;
            }
        }
        //限制时间内的请求次数
        int countWithinTimeLimit = totalCount - expiredCount;
        //如果达到限制，
        if (countWithinTimeLimit > countLimit) {
            response.setStatusCode(HttpStatus.FORBIDDEN); // 状态码403:Forbidden
            log.debug("=====>IP:" + clientIp + " 请求超过限制，禁止访问！");
            String data = "请求超过限制，禁止访问！";
            DataBuffer wrap = response.bufferFactory().wrap(data.getBytes());
            return response.writeWith(Mono.just(wrap));
        }

        // 合法请求，放行，执行后续的过滤器
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return 1;
    }


}

